package com.zt.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zt.entity.Coupons;
import com.zt.service.CouponCacheService;
import com.zt.vo.CouponVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 优惠券缓存服务实现
 */
@Service
@Slf4j
public class CouponCacheServiceImpl implements CouponCacheService {

    @Autowired
    @Qualifier("stringRedisTemplate")
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    // Redis键前缀
    private static final String COUPON_KEY_PREFIX = "coupon:info:";
    private static final String COUPON_STOCK_PREFIX = "coupon:stock:";
    private static final String COUPON_EXPIRE_PREFIX = "coupon:expire:";
    private static final String USER_COUPON_PREFIX = "user:coupon:";
    private static final String COUPON_LIST_PREFIX = "coupon:list:";

    // 缓存过期时间
    private static final long COUPON_CACHE_TTL = 24; // 24小时
    private static final long COUPON_LIST_CACHE_TTL = 30; // 30分钟

    @Override
    public void cacheCoupon(Coupons coupon) {
        try {
            String key = COUPON_KEY_PREFIX + coupon.getId();
            String value = objectMapper.writeValueAsString(coupon);
            redisTemplate.opsForValue().set(key, value, COUPON_CACHE_TTL, TimeUnit.HOURS);
            log.debug("缓存优惠券信息: {}", coupon.getId());
        } catch (Exception e) {
            log.error("缓存优惠券信息失败: {}", coupon.getId(), e);
        }
    }

    @Override
    public Coupons getCachedCoupon(Integer couponId) {
        try {
            String key = COUPON_KEY_PREFIX + couponId;
            String value = redisTemplate.opsForValue().get(key);
            if (value != null) {
                return objectMapper.readValue(value, Coupons.class);
            }
        } catch (Exception e) {
            log.error("获取缓存优惠券信息失败: {}", couponId, e);
        }
        return null;
    }

    @Override
    public void deleteCouponCache(Integer couponId) {
        try {
            String couponKey = COUPON_KEY_PREFIX + couponId;
            String stockKey = COUPON_STOCK_PREFIX + couponId;
            String expireKey = COUPON_EXPIRE_PREFIX + couponId;
            
            redisTemplate.delete(couponKey);
            redisTemplate.delete(stockKey);
            redisTemplate.delete(expireKey);
            
            log.debug("删除优惠券缓存: {}", couponId);
        } catch (Exception e) {
            log.error("删除优惠券缓存失败: {}", couponId, e);
        }
    }

    @Override
    public void cacheStock(Integer couponId, Integer stock) {
        try {
            String key = COUPON_STOCK_PREFIX + couponId;
            redisTemplate.opsForValue().set(key, stock.toString(), COUPON_CACHE_TTL, TimeUnit.HOURS);
            log.debug("缓存优惠券库存: {} -> {}", couponId, stock);
        } catch (Exception e) {
            log.error("缓存优惠券库存失败: {}", couponId, e);
        }
    }

    @Override
    public Integer getStock(Integer couponId) {
        try {
            String key = COUPON_STOCK_PREFIX + couponId;
            String value = redisTemplate.opsForValue().get(key);
            if (value != null) {
                return Integer.parseInt(value);
            }
        } catch (Exception e) {
            log.error("获取优惠券库存失败: {}", couponId, e);
        }
        return null;
    }

    @Override
    public Long decreaseStock(Integer couponId, Integer count) {
        try {
            String key = COUPON_STOCK_PREFIX + couponId;
            Long result = redisTemplate.opsForValue().decrement(key, count);
            if (result < 0) {
                // 库存不足，回滚
                redisTemplate.opsForValue().increment(key, count);
                return -1L;
            }
            log.debug("减少优惠券库存: {} -> 剩余: {}", couponId, result);
            return result;
        } catch (Exception e) {
            log.error("减少优惠券库存失败: {}", couponId, e);
            return -1L;
        }
    }

    @Override
    public Long increaseStock(Integer couponId, Integer count) {
        try {
            String key = COUPON_STOCK_PREFIX + couponId;
            Long result = redisTemplate.opsForValue().increment(key, count);
            log.debug("增加优惠券库存: {} -> 总计: {}", couponId, result);
            return result;
        } catch (Exception e) {
            log.error("增加优惠券库存失败: {}", couponId, e);
            return 0L;
        }
    }

    @Override
    public void setCouponExpire(Integer couponId, Long expireSeconds) {
        try {
            String key = COUPON_EXPIRE_PREFIX + couponId;
            redisTemplate.opsForValue().set(key, "expired", expireSeconds, TimeUnit.SECONDS);
            log.debug("设置优惠券过期时间: {} -> {}秒", couponId, expireSeconds);
        } catch (Exception e) {
            log.error("设置优惠券过期时间失败: {}", couponId, e);
        }
    }

    @Override
    public Boolean isCouponExpired(Integer couponId) {
        try {
            String key = COUPON_EXPIRE_PREFIX + couponId;
            return !redisTemplate.hasKey(key);
        } catch (Exception e) {
            log.error("检查优惠券过期状态失败: {}", couponId, e);
            return true;
        }
    }

    @Override
    public void cacheUserCouponRecord(Integer userId, Integer couponId) {
        try {
            // 已禁用非coupons:键的缓存 - 只保留coupons:开头的键
            // String key = USER_COUPON_PREFIX + userId + ":" + couponId;
            // redisTemplate.opsForValue().increment(key, 1);
            // redisTemplate.expire(key, COUPON_CACHE_TTL, TimeUnit.HOURS);
            log.debug("缓存用户优惠券领取记录已禁用: 用户{} -> 优惠券{}", userId, couponId);
        } catch (Exception e) {
            log.error("缓存用户优惠券领取记录失败: 用户{} -> 优惠券{}", userId, couponId, e);
        }
    }

    @Override
    public Integer getUserCouponCount(Integer userId, Integer couponId) {
        try {
            String key = USER_COUPON_PREFIX + userId + ":" + couponId;
            String value = redisTemplate.opsForValue().get(key);
            return value != null ? Integer.parseInt(value) : 0;
        } catch (Exception e) {
            log.error("获取用户优惠券领取数量失败: 用户{} -> 优惠券{}", userId, couponId, e);
            return 0;
        }
    }

    @Override
    public void clearAllCouponCache() {
        try {
            // 只清除coupons:开头的键，保留其他优惠券相关缓存
            redisTemplate.delete(redisTemplate.keys(COUPON_KEY_PREFIX + "*"));
            // 禁用清除非coupons:开头的键
            // redisTemplate.delete(redisTemplate.keys(COUPON_STOCK_PREFIX + "*"));
            // redisTemplate.delete(redisTemplate.keys(COUPON_EXPIRE_PREFIX + "*"));
            // redisTemplate.delete(redisTemplate.keys(USER_COUPON_PREFIX + "*"));
            // redisTemplate.delete(redisTemplate.keys(COUPON_LIST_PREFIX + "*"));
            log.info("清除coupons:开头的优惠券缓存完成");
        } catch (Exception e) {
            log.error("清除优惠券缓存失败", e);
        }
    }

    @Override
    public void batchCacheCoupons(List<CouponVO> coupons) {
        try {
            // 已禁用非coupons:键的缓存
            // String key = COUPON_LIST_PREFIX + "all";
            // String value = objectMapper.writeValueAsString(coupons);
            // redisTemplate.opsForValue().set(key, value, COUPON_LIST_CACHE_TTL, TimeUnit.MINUTES);
            log.debug("批量缓存优惠券列表已禁用: {} 条", coupons.size());
        } catch (Exception e) {
            log.error("批量缓存优惠券列表失败", e);
        }
    }

    @Override
    public List<CouponVO> getCachedCouponList(String cacheKey) {
        try {
            // 已禁用非coupons:键的缓存获取
            // String key = COUPON_LIST_PREFIX + cacheKey;
            // String value = redisTemplate.opsForValue().get(key);
            // if (value != null) {
            //     return objectMapper.readValue(value, new TypeReference<List<CouponVO>>() {});
            // }
            log.debug("获取缓存优惠券列表已禁用: {}", cacheKey);
        } catch (Exception e) {
            log.error("获取缓存优惠券列表失败: {}", cacheKey, e);
        }
        return null;
    }
}
